<template>
  <div class="deploy-detail p-4">
    <el-card v-loading="loading" class="box-card">
      <template #header>
        <div class="card-header flex items-center justify-between">
          <div class="flex items-center">
            <h2 class="text-xl font-bold mr-4">部署详情</h2>
            <el-tag v-if="deployInfo" :type="getStatusTag(deployInfo.status)" size="large">
              {{ getStatusName(deployInfo.status) }}
            </el-tag>
          </div>
          <div>
            <el-button @click="goBack">返回</el-button>
            <el-button 
              v-if="deployInfo?.status === DeployStatus.FAILED" 
              type="warning" 
              @click="handleRetry"
            >重试部署</el-button>
            <el-button 
              v-if="deployInfo?.status === DeployStatus.PROCESSING" 
              type="danger" 
              @click="handleCancel"
            >取消部署</el-button>
          </div>
        </div>
      </template>

      <div v-if="deployInfo">
        <!-- 部署基本信息 -->
        <div class="info-section bg-gray-50 p-4 rounded-md mb-6">
          <h3 class="text-lg font-semibold mb-4">基本信息</h3>
          
          <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
            <div>
              <div class="text-gray-500 text-sm mb-1">项目名称</div>
              <div>{{ deployInfo.projectName }}</div>
            </div>
            
            <div>
              <div class="text-gray-500 text-sm mb-1">部署环境</div>
              <div>
                <el-tag :type="getEnvironmentTag(deployInfo.environment)">
                  {{ getEnvironmentName(deployInfo.environment) }}
                </el-tag>
              </div>
            </div>
            
            <div>
              <div class="text-gray-500 text-sm mb-1">版本号</div>
              <div>{{ deployInfo.version }}</div>
            </div>
            
            <div>
              <div class="text-gray-500 text-sm mb-1">创建时间</div>
              <div>{{ deployInfo.createTime }}</div>
            </div>
            
            <div>
              <div class="text-gray-500 text-sm mb-1">最后更新时间</div>
              <div>{{ deployInfo.updateTime }}</div>
            </div>
            
            <div>
              <div class="text-gray-500 text-sm mb-1">部署状态</div>
              <div>
                <el-tag :type="getStatusTag(deployInfo.status)">
                  {{ getStatusName(deployInfo.status) }}
                </el-tag>
              </div>
            </div>
          </div>
        </div>
        
        <!-- 部署进度 -->
        <div class="progress-section mb-6">
          <h3 class="text-lg font-semibold mb-4">部署进度</h3>
          
          <el-steps :active="activeStep" :process-status="processStatus" finish-status="success" align-center>
            <el-step 
              v-for="(step, index) in deployInfo.steps" 
              :key="index" 
              :title="getStepTitle(step.step)"
              :status="getStepStatus(step.status)"
            >
              <template #description>
                <div class="step-desc">
                  <p>{{ getStepDescription(step.step) }}</p>
                  <p v-if="step.startTime" class="text-xs text-gray-500">
                    开始时间: {{ step.startTime }}
                  </p>
                  <p v-if="step.endTime" class="text-xs text-gray-500">
                    结束时间: {{ step.endTime }}
                  </p>
                  <p v-if="step.message" class="text-xs" :class="step.status === DeployStatus.FAILED ? 'text-red-500' : 'text-gray-500'">
                    {{ step.message }}
                  </p>
                </div>
              </template>
            </el-step>
          </el-steps>
        </div>
        
        <!-- 部署日志 -->
        <div class="log-section mb-6">
          <h3 class="text-lg font-semibold mb-2">部署日志</h3>
          
          <div class="flex justify-end mb-2">
            <el-button v-if="shouldPollLog" size="small" type="primary" plain @click="toggleLogPolling">
              {{ isPollingLog ? '停止刷新' : '自动刷新' }}
            </el-button>
            <el-button size="small" type="primary" plain @click="fetchDeployLog">刷新日志</el-button>
          </div>
          
          <el-card shadow="never" class="log-card">
            <pre v-if="deployInfo.log" class="log-content">{{ deployInfo.log }}</pre>
            <div v-else class="text-gray-500 text-center py-4">暂无日志</div>
          </el-card>
        </div>
      </div>
      
      <div v-else-if="!loading" class="text-center py-8">
        <el-empty description="未找到部署信息"></el-empty>
      </div>
    </el-card>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getDeployDetail, getDeployLog, cancelDeploy, retryDeploy } from '@/request/deploy-api'
import { DeployEnvironment, DeployStatus, DeployStep, type DeployRecord, type DeployDetail, type DeployStepStatus } from '@/model/deploy-model'

defineOptions({
  name: 'DeployDetail'
})

const route = useRoute()
const router = useRouter()
const loading = ref(false)
const deployInfo = ref<DeployRecord | null>(null)
const isPollingLog = ref(false)
const pollingInterval = ref<number | null>(null)
const logPosition = ref(0)

// 获取当前部署ID
const deployId = computed(() => route.params.id as string)

// 是否应该自动刷新日志
const shouldPollLog = computed(() => {
  if (!deployInfo.value) return false
  return deployInfo.value.status === DeployStatus.PROCESSING || 
         deployInfo.value.status === DeployStatus.PENDING
})

// 当前活跃步骤
const activeStep = computed(() => {
  if (!deployInfo.value || !deployInfo.value.steps) return 0
  
  const processing = deployInfo.value.steps.findIndex(s => s.status === DeployStatus.PROCESSING)
  if (processing !== -1) return processing
  
  const failed = deployInfo.value.steps.findIndex(s => s.status === DeployStatus.FAILED)
  if (failed !== -1) return failed
  
  // 如果全部成功，则显示最后一个步骤
  const successCount = deployInfo.value.steps.filter(s => s.status === DeployStatus.SUCCESS).length
  return successCount
})

// 当前处理状态
const processStatus = computed(() => {
  if (!deployInfo.value) return 'process'
  
  switch (deployInfo.value.status) {
    case DeployStatus.SUCCESS:
      return 'success'
    case DeployStatus.FAILED:
      return 'error'
    case DeployStatus.PROCESSING:
      return 'process'
    default:
      return 'wait'
  }
})

// 获取部署详情（silent=true 时不展示全局loading，便于轮询）
const fetchDeployDetail = async (silent = false) => {
  if (!silent) loading.value = true
  try {
    const response = await getDeployDetail(deployId.value)
    if (response.code === 0 && response.data) {
      // 转换API返回的数据格式为组件需要的格式
      const detail = response.data as DeployDetail
      
      // 根据API文档补充必要的字段
      const record: DeployRecord = {
        id: String(detail.id),
        projectId: String(detail.project_version_id),
        projectName: 'Project', // 默认名称，实际中应该从项目版本中获取
        environment: detail.environment as DeployEnvironment,
        status: detail.status,
        version: '1.0.0', // 默认版本号，实际中应该从项目版本中获取
        // 模拟部署步骤，实际中应该根据部署状态生成
        steps: [
          { 
            step: DeployStep.UPLOAD, 
            status: detail.status === DeployStatus.SUCCESS ? DeployStatus.SUCCESS : 
                   detail.status === DeployStatus.FAILED ? DeployStatus.FAILED : DeployStatus.PROCESSING,
            startTime: detail.started_at,
            endTime: detail.completed_at
          }
        ],
        log: detail.logs || '',
        createTime: detail.started_at,
        updateTime: detail.completed_at || detail.started_at
      }
      
      deployInfo.value = record
      
      // 首次加载时，将日志指针对齐到服务器日志长度，避免从0开始再次拼接造成重复
      const serverLogLen = (detail.logs || '').length
      if (logPosition.value === 0 && serverLogLen > 0) {
        logPosition.value = serverLogLen
      }
      
      if (deployInfo.value && deployInfo.value.steps) {
        try {
          const stepProcIdx = deployInfo.value.steps.findIndex(s => s.status === DeployStatus.PROCESSING)
          // 调试输出用于排查状态推进
          console.debug(
            `[detail] id=${deployId.value} status=${deployInfo.value.status} stepProcIdx=${stepProcIdx} logLen=${serverLogLen}`
          )
        } catch {}
      }
      
      // 如果部署正在进行中，自动开启日志轮询
      if (shouldPollLog.value && !isPollingLog.value) {
        toggleLogPolling()
      }
    } else {
      ElMessage.error(response.errorMsg || '获取部署详情失败')
    }
  } catch (error) {
    console.error('获取部署详情失败:', error)
    ElMessage.error('获取部署详情失败')
  } finally {
    if (!silent) loading.value = false
  }
}
}

// 获取部署日志
const fetchDeployLog = async () => {
  if (!deployInfo.value) return
  
  try {
    const response = await getDeployLog({
      deployId: deployId.value,
      from: logPosition.value
    })
    const chunk = response.data
    if (chunk) {
      if (!deployInfo.value.log) {
        deployInfo.value.log = chunk
      } else {
        deployInfo.value.log += chunk
      }
      // 更新日志位置，用于增量获取
      logPosition.value += chunk.length
      try {
        console.debug(`[log] id=${deployId.value} from=${logPosition.value - chunk.length} +${chunk.length} total=${deployInfo.value.log.length}`)
      } catch {}
    }
  } catch (error) {
    console.error('获取部署日志失败:', error)
  }
}

// 切换日志轮询
const toggleLogPolling = () => {
  if (isPollingLog.value) {
    // 停止轮询
    if (pollingInterval.value) {
      window.clearInterval(pollingInterval.value)
      pollingInterval.value = null
    }
    isPollingLog.value = false
    try { console.debug(`[poll] stop for id=${deployId.value}`) } catch {}
  } else {
    // 开始轮询
    // 先标记为轮询中，避免详情获取内再次触发轮询导致重复定时器
    isPollingLog.value = true
    try { console.debug(`[poll] start for id=${deployId.value}`) } catch {}
    fetchDeployDetail(true)
    fetchDeployLog()
    pollingInterval.value = window.setInterval(() => {
      // 同步刷新详情与日志，保证状态与步骤推进
      fetchDeployDetail(true)
      fetchDeployLog()
      // 如果部署已完成，自动停止轮询
      if (deployInfo.value && 
          (deployInfo.value.status === DeployStatus.SUCCESS || 
           deployInfo.value.status === DeployStatus.FAILED)) {
        toggleLogPolling()
      }
    }, 3000) // 天3秒轮询一次
  }
}

// 获取步骤标题
const getStepTitle = (step: DeployStep) => {
  switch (step) {
    case DeployStep.UPLOAD:
      return '上传项目包'
    case DeployStep.EXTRACT:
      return '解压项目包'
    case DeployStep.COPY_CONFIG:
      return '拷贝配置文件'
    case DeployStep.NPM_INSTALL:
      return 'NPM 安装依赖'
    case DeployStep.NPM_BUILD:
      return 'NPM 构建项目'
    case DeployStep.RESTART:
      return '重启服务'
    case DeployStep.COMPLETE:
      return '完成部署'
    default:
      return step
  }
}

// 获取步骤描述
const getStepDescription = (step: DeployStep) => {
  switch (step) {
    case DeployStep.UPLOAD:
      return '上传项目包到服务器'
    case DeployStep.EXTRACT:
      return '解压项目包到指定目录'
    case DeployStep.COPY_CONFIG:
      return '拷贝配置文件到项目目录'
    case DeployStep.NPM_INSTALL:
      return '安装项目依赖'
    case DeployStep.NPM_BUILD:
      return '构建前端项目'
    case DeployStep.RESTART:
      return '重启后端服务'
    case DeployStep.COMPLETE:
      return '部署流程完成'
    default:
      return ''
  }
}

// 获取步骤状态
const getStepStatus = (status: DeployStatus) => {
  switch (status) {
    case DeployStatus.SUCCESS:
      return 'success'
    case DeployStatus.PROCESSING:
      return 'process'
    case DeployStatus.FAILED:
      return 'error'
    default:
      return 'wait'
  }
}

// 获取环境标签类型
const getEnvironmentTag = (environment: DeployEnvironment) => {
  switch (environment) {
    case DeployEnvironment.DEVELOPMENT:
      return 'info'
    case DeployEnvironment.TESTING:
      return 'warning'
    case DeployEnvironment.PRODUCTION:
      return 'danger'
    default:
      return 'info'
  }
}

// 获取环境名称
const getEnvironmentName = (environment: DeployEnvironment) => {
  switch (environment) {
    case DeployEnvironment.DEVELOPMENT:
      return '开发环境'
    case DeployEnvironment.TESTING:
      return '测试环境'
    case DeployEnvironment.PRODUCTION:
      return '生产环境'
    default:
      return environment
  }
}

// 获取状态标签类型
const getStatusTag = (status: DeployStatus) => {
  switch (status) {
    case DeployStatus.SUCCESS:
      return 'success'
    case DeployStatus.PROCESSING:
      return 'warning'
    case DeployStatus.PENDING:
      return 'info'
    case DeployStatus.FAILED:
      return 'danger'
    default:
      return 'info'
  }
}

// 获取状态名称
const getStatusName = (status: DeployStatus) => {
  switch (status) {
    case DeployStatus.SUCCESS:
      return '成功'
    case DeployStatus.PROCESSING:
      return '部署中'
    case DeployStatus.PENDING:
      return '待部署'
    case DeployStatus.FAILED:
      return '失败'
    default:
      return status
  }
}

// 处理重试
const handleRetry = () => {
  if (!deployInfo.value) return
  
  ElMessageBox.confirm(`确认重试部署 "${deployInfo.value.projectName}" 吗？`, '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  })
    .then(async () => {
      try {
        await retryDeploy(deployId.value)
        ElMessage.success('重试操作已提交')
        fetchDeployDetail(false)
      } catch (error) {
        console.error('重试部署失败:', error)
        ElMessage.error('重试部署失败')
      }
    })
    .catch(() => {
      // 取消操作
    })
}

// 处理取消
const handleCancel = () => {
  if (!deployInfo.value) return
  
  ElMessageBox.confirm(`确认取消部署 "${deployInfo.value.projectName}" 吗？`, '警告', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  })
    .then(async () => {
      try {
        await cancelDeploy(deployId.value)
        ElMessage.success('已取消部署')
        fetchDeployDetail(false)
      } catch (error) {
        console.error('取消部署失败:', error)
        ElMessage.error('取消部署失败')
      }
    })
    .catch(() => {
      // 取消操作
    })
}

// 返回
const goBack = () => {
  router.push('/deploy/list')
}

onMounted(() => {
  fetchDeployDetail(false)
})

onBeforeUnmount(() => {
  // 组件卸载前清除定时器
  if (pollingInterval.value) {
    window.clearInterval(pollingInterval.value)
  }
  pollingInterval.value = null
  isPollingLog.value = false
})
</script>

<style scoped lang="scss">
.deploy-detail {
  .log-card {
    max-height: 400px;
    overflow-y: auto;
  }
  
  .log-content {
    font-family: 'Courier New', Courier, monospace;
    font-size: 14px;
    white-space: pre-wrap;
    word-break: break-all;
  }
  
  .step-desc {
    padding: 0 4px;
  }
}
</style>
